package cgl.sensorgrid.sopac.gps.filters;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.LinkedList;
import java.util.Properties;
import java.util.Queue;
import java.util.Random;
import java.util.StringTokenizer;

import cgl.hpsearch.common.Sys;
import cgl.narada.event.NBEvent;
import cgl.sensorgrid.common.PropertyFile;
import cgl.sensorgrid.filters.Filter;
import cgl.sensorgrid.sopac.gps.threadpool.ThreadPool;
import cgl.sensorgrid.sopac.gps.filters.UtilSet;

public class RealtimeRdahmmRunner extends Filter {
	
	protected class RealtimeRdahmmSite {
		private String siteName;
		private String modelFilePrefix;
		private long lastRemodelTimeMilli;
		private long modelInputStartMilli;
		private long lastEvalTimeMilli;
		private boolean isModelBuilt;
		private String siteModelDir;
		private String siteEvalDir;
		private String siteHistDir;
		private FileWriter fwModel;
		private FileWriter fwEval;
		private FileWriter fwHist;
		private Calendar calLastHistData;
		private boolean lastModelUsableValue;
		private LinkedList stateChangeTimes;
		
		public RealtimeRdahmmSite(String siteName, String modelParentDir, String evalParentDir,
									String histParentDir) {
			this.siteName = siteName;
			modelFilePrefix = siteName + "_model";
			fwModel = null;
			fwEval = null;
			fwHist = null;
			calLastHistData = null;
			lastRemodelTimeMilli = 0;
			lastEvalTimeMilli = 0;
			siteModelDir = modelParentDir + File.separator + siteName + File.separator;
			siteEvalDir = evalParentDir + File.separator + siteName + File.separator;
			siteHistDir = histParentDir + File.separator + siteName + File.separator;
			stateChangeTimes = new LinkedList();
			
			File fDir = new File(siteModelDir);
			if (!fDir.exists())
				fDir.mkdirs();
			fDir = new File(siteEvalDir);
			if (!fDir.exists())
				fDir.mkdirs();
			fDir = new File(siteHistDir);
			if (!fDir.exists())
				fDir.mkdirs();
			
			checkModelExists();
			lastModelUsableValue = false;
		}

		public String getSiteName() {
			return siteName;
		}

		public void setSiteName(String siteName) {
			this.siteName = siteName;
		}

		public boolean isModelBuilt() {
			return isModelBuilt;
		}

		public void setModelBuilt(boolean isModelBuilt) {
			this.isModelBuilt = isModelBuilt;
		}

		public long getLastRemodelTimeMilli() {
			return lastRemodelTimeMilli;
		}

		public void setLastRemodelTimeMilli(long lastRemodelTimeMilli) {
			this.lastRemodelTimeMilli = lastRemodelTimeMilli;
		}

		public long getLastEvalTimeMilli() {
			return lastEvalTimeMilli;
		}

		public void setLastEvalTimeMilli(long lastEvalTimeMilli) {
			this.lastEvalTimeMilli = lastEvalTimeMilli;
		}
		
		public void checkModelExists() {
			File fModel = new File(siteModelDir + modelFilePrefix + ".Q");
			isModelBuilt = fModel.exists();
			if (isModelBuilt) {
				lastRemodelTimeMilli = fModel.lastModified();
				// if the present time has passed the remodel period, we'll need to rebuild the model
				if (remodelPeriodMilli > 0 &&
					System.currentTimeMillis() - lastRemodelTimeMilli >= remodelPeriodMilli) {
					isModelBuilt = false;
				}
			}
		}
		
		public void addLine(String line) {
			if (isHistSaved)
				addHistData(line);
			if (!isModelBuilt) {
				// add this line to the model input file, and build the model 
				// if modelDataTimeMilli's data has been collected
				try {
					if (fwModel == null) {
						fwModel = new FileWriter(siteModelDir + modelFilePrefix + ".xyz", false);
						modelInputStartMilli = System.currentTimeMillis();					
					}
					
					fwModel.write(line);
					if (System.currentTimeMillis() - modelInputStartMilli >= modelDataTimeMilli) {
						fwModel.flush();
						fwModel.close();
						buildModel();
						fwModel = null;
					}
				} catch (Exception e) {
					e.printStackTrace();
				}
			} 
			
			// try to do evaluation
			boolean modelUsable = isModelBuilt;
			if (!modelUsable) {
				// if a new model has not been built, check if there is an old one to use
				File fModel = new File(siteModelDir + modelFilePrefix + ".Q");				
				if (fModel.exists()) {
					long timeSinceLastModel = System.currentTimeMillis() - fModel.lastModified();
					modelUsable = timeSinceLastModel < (remodelPeriodMilli + modelDataTimeMilli + evalPeriodMilli);
					if (modelUsable && modelUsable != lastModelUsableValue)
						log("old model usable for site" + siteName);
				}
			}
			lastModelUsableValue = modelUsable;
			if (modelUsable) {
				// add this line to the evaluation input file, and do evaluation if the 
				// evaluation data has been collected for as long as evalPeriodMilli
				try {
					if (fwEval == null) {
						fwEval = new FileWriter(siteEvalDir + siteName + ".xyz", false);
						lastEvalTimeMilli = System.currentTimeMillis();					
					}
					fwEval.write(line);
					if (System.currentTimeMillis() - lastEvalTimeMilli >= evalPeriodMilli) {
						fwEval.flush();
						fwEval.close();
						evaluate();
						fwEval = null;
						if (remodelPeriodMilli > 0 &&
							System.currentTimeMillis() - lastRemodelTimeMilli >= remodelPeriodMilli) {
							isModelBuilt = false;
						}
					}
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		}
		
		protected void buildModel() {		
			// run rdahmm script in a separate thread
			ModelThread mt = new ModelThread(rdahmmTrainShellPath, siteModelDir + modelFilePrefix + ".xyz", modelThreadPool);
			mt.start();
			lastRemodelTimeMilli = System.currentTimeMillis();
			isModelBuilt = true;
		}
		
		protected void evaluate() {
			String input = siteEvalDir + siteName + ".xyz";
			String command = rdahmmEvalShellPath + " " + input + " 5 " + modelFilePrefix + " " + siteModelDir;
			String out = exec(command);
			if (out.length() > 0) {
				log("Results for RDAHMM evaluation for " + siteName + ":" + out);
			} else {
				log("Sucessfully done RDAHMM evaluation for " + siteName);
			}
			
			// run plot script.
			String xyzFilePath = input + ".xyz";
			String QFilePath = siteEvalDir + siteName + ".Q";
			command = plotShellPath + " " + xyzFilePath + " " + QFilePath;
			out = exec(command);
			if (out.length() > 0) {
				log("Results for plotting for " + siteName + ":" + out);
			} else {
				log("Sucessfully plotted for " + siteName);
			}
			
			lastEvalTimeMilli = System.currentTimeMillis();
			
			checkStateChange(input, QFilePath);
			recordStateChangeSummary();
		}
		
		protected void checkStateChange(String inputFilePath, String qFilePath) {
			try {
				String line1, line2, inputChange, input2;
				BufferedReader brQ = new BufferedReader(new FileReader(qFilePath));
				line1 = brQ.readLine();
				line2 = brQ.readLine();
				
				BufferedReader brInput = new BufferedReader(new FileReader(inputFilePath));
				input2 = brInput.readLine();
				input2 = brInput.readLine();
				
				inputChange = null;
				// looking for state changes
				while (line2 != null) {
					if (!line1.equals(line2)) {
						inputChange = input2;
						publishData(makeResultMsg(line1, line2, input2).getBytes());
					}
					line1 = line2;
					line2 = brQ.readLine();
					input2 = brInput.readLine();
				}
				brQ.close();
				brInput.close();
				
				// if there a state change, record the time of it
				if (inputChange != null) {
					// input2 is like "P483    2008-09-05      11:36:52PM-EST	..."
					System.out.println("line1 in checkStateChange:" + inputChange);
					int tab1, tab2, tab3;
					tab1 = inputChange.indexOf('\t');
					tab2 = inputChange.indexOf('\t', tab1+1);
					tab3 = inputChange.indexOf('\t', tab2+1);
					Calendar changeTime = Calendar.getInstance();
					UtilSet.setDateByString(changeTime, inputChange.substring(tab1+1, tab2));
					String timeStr = inputChange.substring(tab2+1, tab3);
					System.out.println("timeStr in checkStateChange:" + timeStr);
					int colon1 = timeStr.indexOf(':');
					int colon2 = timeStr.indexOf(':', colon1+1);
					int posAMPM = timeStr.indexOf('M') - 1;
					changeTime.set(Calendar.HOUR, Integer.parseInt(timeStr.substring(0, colon1)));
					changeTime.set(Calendar.MINUTE, Integer.parseInt(timeStr.substring(colon1+1, colon2)));
					changeTime.set(Calendar.SECOND, Integer.parseInt(timeStr.substring(colon2+1, posAMPM)));
					if (timeStr.charAt(posAMPM) == 'A')
						changeTime.set(Calendar.AM_PM, Calendar.AM);
					else
						changeTime.set(Calendar.AM_PM, Calendar.PM);
					
					stateChangeTimes.add(changeTime);
					if (stateChangeTimes.size() > (86400000 / evalPeriodMilli))
						stateChangeTimes.remove();
					System.out.println("state change found for " + siteName + " at "
										+ getDateString(changeTime, true));
				} else {
					stateChangeTimes.add(null);
				}			
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
		
		protected String makeResultMsg(String oldStatus, String newStatus, String inputLine) {
			// inputLine is like "P483    2008-09-05      11:36:52PM-EST	..."
			int tab1, tab2, tab3;
			tab1 = inputLine.indexOf('\t');
			tab2 = inputLine.indexOf('\t', tab1+1);
			tab3 = inputLine.indexOf('\t', tab2+1);
			
			String stationName = inputLine.substring(0, tab1).toLowerCase();
			
			Calendar changeTime = Calendar.getInstance();
			UtilSet.setDateByString(changeTime, inputLine.substring(tab1+1, tab2));
			String timeStr = inputLine.substring(tab2+1, tab3);
			System.out.println("timeStr in checkStateChange:" + timeStr);
			int colon1 = timeStr.indexOf(':');
			int colon2 = timeStr.indexOf(':', colon1+1);
			int posAMPM = timeStr.indexOf('M') - 1;
			int hour = Integer.parseInt(timeStr.substring(0, colon1));
			if (timeStr.charAt(posAMPM) == 'P' && hour < 12)
				hour += 12;
			changeTime.set(Calendar.HOUR_OF_DAY, hour);
			changeTime.set(Calendar.MINUTE, Integer.parseInt(timeStr.substring(colon1+1, colon2)));
			changeTime.set(Calendar.SECOND, Integer.parseInt(timeStr.substring(colon2+1, posAMPM)));
			
			return stationName + ';' + UtilSet.getDateTimeString(changeTime) + ';' 
					+ oldStatus + "to" + newStatus + "\nEOF\n";
		}
		
		/**
		 * check if the station has changed its state recently within timeRange
		 * @param timeRange
		 * @return
		 */
		public boolean isChangedInRecent(long timeRange) {
			Calendar now = Calendar.getInstance();
			// the last change time is the latest time
			for (int i=stateChangeTimes.size()-1; i>=0; i--) {
				Calendar changeTime = (Calendar)stateChangeTimes.get(i);
				if (changeTime != null) {
					if (now.getTimeInMillis() - changeTime.getTimeInMillis() <= timeRange)
						return true;
					else
						return false;
				}
			}
			
			return false;
		}
		
		protected void addHistData(String line) {
			// we use one file to save one day's data. the directory structure of a file is like
			// histParentDir/siteName/yyyy/mm/sietName_yyyy-mm-dd.dat			
			Calendar now = Calendar.getInstance();
			if (calLastHistData == null || fwHist == null 
				|| now.get(Calendar.YEAR) > calLastHistData.get(Calendar.YEAR)
				|| now.get(Calendar.MONTH) > calLastHistData.get(Calendar.MONTH)
				|| now.get(Calendar.DAY_OF_MONTH) > calLastHistData.get(Calendar.DAY_OF_MONTH)) {
				try {
					if (fwHist != null) {
						fwHist.flush();
						fwHist.close();
					}
					String histFileDir = siteHistDir + now.get(Calendar.YEAR) + File.separator
											+ (now.get(Calendar.MONTH) + 1) + File.separator;
					File fDir = new File(histFileDir);
					if (!fDir.exists())
						fDir.mkdirs();
					String histFilePath = histFileDir + siteName + "_" + getDateString(now, false) + ".dat";
					fwHist = new FileWriter(histFilePath, true);
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
			
			try {
				fwHist.write(line);
			} catch (Exception e) {
				e.printStackTrace();
			}			
			calLastHistData = now;			
		}
	}
	
	protected class MessageProcessor extends Thread {
		public void run() {
			boolean running = true;
			try {
				while (running) {
					synchronized (listCV) {
						if (eventList.size() == 0) {
							listCV.wait();
						}
						NBEvent nbEvent = (NBEvent) eventList.remove(0);
						byte[] data2 = nbEvent.getContentPayload();
						if (data2 != null && data2.length > 0) {
							processMessage(new String(data2));
						}
					}
				}
				return;
			} catch (Exception ex) {
				ex.printStackTrace();
			}
		}
	}

	// realtime rdahmm parameters got from the configuraion file sensorgrid.properties 
	protected static Properties properties = null;
	protected static long dayMilli = 86400 * 1000;
	protected static long remodelPeriodMilli = -1;
	protected static long evalPeriodMilli = -1;
	protected static long modelDataTimeMilli = -1;
	protected static String dataDir = null;
	protected static String evalDir = null;
	protected static String histDir = null;
	protected static String rdahmmTrainShellPath = null;
	protected static String rdahmmEvalShellPath = null;
	protected static String plotShellPath = null;
	protected static boolean isHistSaved = false;
	protected static Calendar calNow = Calendar.getInstance();
	
	/** the name of the network that this process is running for */
	protected String networkName;	
	
	protected MessageProcessor msgProcessor;
	protected Hashtable sitesTable;
	protected LinkedList eventList;
	protected Object listCV;	// conditional variable for waiting and notifying on eventList 
	protected ThreadPool modelThreadPool;
	
	public RealtimeRdahmmRunner(String commType, String nbHost, String nbPort, String subTopic, String pubTopic, String networkName) {
		sitesTable = new Hashtable();
		eventList = new LinkedList();
		listCV = new Object();
		this.networkName = networkName;
		loadProperties();
		
		String[] initArgs = {commType, nbHost, nbPort, subTopic, pubTopic};
		//modelThreadPool = new ThreadPool(30);
		modelThreadPool = null;
		initialize(initArgs);
		msgProcessor = new MessageProcessor();
		msgProcessor.start();
	}
	
	protected void loadProperties() {
		if (properties !=  null) {
			return;
		}
		
		try {
			properties = PropertyFile.loadProperties("sensorgrid.properties");
			evalDir = properties.getProperty("rdahmm.eval.directory");
			dataDir = properties.getProperty("rdahmm.data.directory");
			histDir = properties.getProperty("rdahmm.hist.directory");
			rdahmmTrainShellPath = properties.getProperty("rdahmm.trainshell.directory");
			rdahmmEvalShellPath = properties.getProperty("rdahmm.evalshell.directory");
			plotShellPath = properties.getProperty("rdahmm.plotshell.directory");
			remodelPeriodMilli = Long.parseLong(properties.getProperty("rdahmm.remodel.days")) * dayMilli;
			evalPeriodMilli = Long.parseLong(properties.getProperty("rdahmm.eval.minutes")) * 60000;
			modelDataTimeMilli = Long.parseLong(properties.getProperty("rdahmm.modeldata.hours")) * 60 * 60000;
			isHistSaved = Boolean.parseBoolean(properties.getProperty("rdahmm.save.hist"));
			log("[RdahmmFilter] --> Rdahmm Application Directory = "	+ evalDir);
			log("[RdahmmFilter] --> Rdahmm Data Directory = " + dataDir);
		} catch (Exception e) {
			e.printStackTrace();
		}
		
		if (properties == null || evalDir == null || dataDir == null 
			|| rdahmmTrainShellPath == null || rdahmmEvalShellPath == null
			|| plotShellPath == null || remodelPeriodMilli == -1 || evalPeriodMilli == -1) {
			System.err.println("Fatal Error: failed to load properties!");
			System.exit(-1);
		}
	}
	
	public void onEvent(NBEvent nbEvent) {
		if (nbEvent.getContentPayload() != null) {
			synchronized (listCV) {
				eventList.add(nbEvent);
				if (eventList.size() >= 1) {
					listCV.notify();
				}
			}
		}
	}
	
	public void processMessage(String msg) {
		try {
			StringTokenizer st = new StringTokenizer(msg, "\n");
			while (st.hasMoreTokens()) {
				String token = st.nextToken();
				if (!token.startsWith("EOF")) {
					if (token.length() > 4) {
						String siteName = token.substring(0, 4);
						if (sitesTable.get(siteName) != null) {
							RealtimeRdahmmSite rd = (RealtimeRdahmmSite) sitesTable.get(siteName);
							rd.addLine(token + "\n");
						} else {
							RealtimeRdahmmSite rd = new RealtimeRdahmmSite(siteName, dataDir, evalDir, histDir);
							sitesTable.put(siteName, rd);
							rd.addLine(token + '\n');
						}
					}
				}
			}
		} catch (Exception ex) {
			ex.printStackTrace();
		}
	}
	
	/**
	 * save the state change information of every station
	 */
	protected void recordStateChangeSummary() {
		try {
			synchronized (sitesTable) {
				FileWriter fw = new FileWriter(evalDir + File.separator + "state_change_" 
												+ networkName.toLowerCase() + ".txt", false);
				Enumeration e = sitesTable.elements();
				while (e.hasMoreElements()) {
					RealtimeRdahmmSite site = (RealtimeRdahmmSite) e.nextElement();
					// a line of the file is like "raap yes no", where "yes" means the site 
					// raap changed its state in last 2 hours, and "no" means no state change 
					// in last 1 day
					fw.write(site.getSiteName().toLowerCase());
					if (site.isChangedInRecent(7200000))
						fw.write(" yes");
					else
						fw.write(" no");
					
					if (site.isChangedInRecent(86400000))
						fw.write(" yes\n");
					else
						fw.write(" no\n");
				}
				fw.flush();
				fw.close();
			}			
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	/**
	 * Execute a command
	 * 
	 * @param execStr
	 *            String command string
	 * @return String the information of execute result
	 */
	public static String exec(String execStr) {
		Runtime runtime = Runtime.getRuntime();// Get current runtime object
		String outInfo = ""; // execute error information
		try {
			String osname = System.getProperty("os.name");
			String[] args = null;
			if (osname.equals("Linux")) {
				args = new String[] { "sh", "-c", execStr }; // execute
				// linux command
			} else if (osname.substring(0, 3).equals("Win")) {
				args = new String[] { "cmd", "/c", execStr }; // execute
			} else {
				System.exit(0);
			}

			Process proc = runtime.exec(args); // run another process to execute command			
			InputStream out = proc.getInputStream();
			BufferedReader br1 = new BufferedReader(new InputStreamReader(out));
			while (br1.readLine() != null) {
			}
			out.close();

			InputStream in = proc.getErrorStream(); // get error information
			BufferedReader br = new BufferedReader(new InputStreamReader(in));
			String line = "";
			while ((line = br.readLine()) != null) {
				outInfo = outInfo + line + "\n";
			}
			// System.out.println(outInfo);
			in.close();

			try { // check the result
				if (proc.waitFor() != 0) {
					System.err.println("exit value = " + proc.exitValue());
				}
			} catch (InterruptedException e) {
				System.err.print(e);
				e.printStackTrace();
			}

		} catch (IOException e) {
			System.out.println("exec error: " + e.getMessage());
			e.printStackTrace();
		}
		return outInfo;
	}
	
	public static String getDateString(Calendar date, boolean timeWanted) {
		StringBuffer ret = new StringBuffer();
		ret.append(date.get(Calendar.YEAR)).append('-').append(date.get(Calendar.MONTH) + 1);
		ret.append('-').append(date.get(Calendar.DAY_OF_MONTH));
		if (timeWanted) {
			ret.append(' ').append(date.get(Calendar.HOUR_OF_DAY)).append(':');
			ret.append(date.get(Calendar.MINUTE)).append(':').append(date.get(Calendar.SECOND));
		}
		return ret.toString();
	}	
	
	public static void log(String str) {
		calNow.setTimeInMillis(System.currentTimeMillis());
		System.out.println('[' + getDateString(calNow, true) + "] " + str);
	}
	
    public static void copyFileToFile(File sourceFile,File destFile) 
		  throws Exception {
		  InputStream in=new FileInputStream(sourceFile);
		  OutputStream out=new FileOutputStream(destFile);
		  byte[] buf=new byte[1024*16];
		  int length;
		  while((length=in.read(buf))>0) {
				out.write(buf,0,length);
		  }
		  in.close();
		  out.flush();
		  out.close();
    }
	
	protected class ModelThread extends Thread {
		private int threadNum = 10;
		ThreadPool tPool;
		String trainShPath;
		String inputPath;
		double maxLValue = 0;
		
		public ModelThread (String trainShPath, String inputPath, ThreadPool tPool) {
			this.trainShPath = trainShPath;
			this.inputPath = inputPath;
			this.tPool = tPool;
		}
		
		public void run() {
			if (tPool != null)
				modelMultipleOneTries();
			else
				modelDirectTenTries();
		}

		private void modelDirectTenTries() {
			log("starting to build model for " + inputPath);
			String res = exec(trainShPath + " " + inputPath + " 5 1234 10");
			if (res.length() == 0) {
				log("model successfully built");
			} else {
				log("results for building model for " + inputPath + ":");
				log(res);
			}
		}

		private void modelMultipleOneTries() {
			long st = System.currentTimeMillis();
			int idx = inputPath.lastIndexOf(File.separatorChar);
			String sourceDir = inputPath.substring(0, idx);
			String fileName = inputPath.substring(idx+1);
			try {
				ModelOneTry[] oneTryList = new ModelOneTry[threadNum];
				Random random = new Random(1234);
				// copy input file to every temporary directory and train model in that directory
				for (int i=0; i<threadNum; i++) {
					String destDirStr = sourceDir + File.separatorChar + "tmp" + i;
					File destDir = new File(destDirStr);
					destDir.mkdirs();
					String destPath = destDir + File.separator + fileName;
					copyFileToFile(new File(inputPath), new File(destPath));				
					oneTryList[i] = new ModelOneTry(trainShPath, destPath, random.nextInt(9999));
					tPool.assign(oneTryList[i]);
				}
				tPool.complete();
				
				// find the model with the largest L value and copy model files to the input directory				
				maxLValue = oneTryList[0].getLValue();
				int idxMax = 0;
				for (int i=1; i<threadNum; i++) {
					double v = oneTryList[i].getLValue();
					if (v > maxLValue) {
						maxLValue = v;
						idxMax = i;
					}
				}
				File tmpDir = new File(oneTryList[idxMax].getInputDir());
				File[] tmpFiles = tmpDir.listFiles();
				for (int i=0; i<tmpFiles.length; i++) {
					String modelFilePath = sourceDir + File.separator + tmpFiles[i].getName();
					copyFileToFile(tmpFiles[i], new File(modelFilePath));
				}
				
				// delete the temporary directories
				for (int i=0; i<oneTryList.length; i++) {
					tmpDir = new File(oneTryList[i].getInputDir());
					tmpFiles = tmpDir.listFiles();
					for (int j=0; j<tmpFiles.length; j++)
						tmpFiles[j].delete();
					tmpDir.delete();
				}
				
				long et = System.currentTimeMillis();
				log("starting time:" + st + "; ending time:" + et 
									+ "; interval:" + (et - st));
			} catch (Exception e) {
				e.printStackTrace();
			}
		}		
	}
	
	protected class ModelOneTry implements Runnable {
		protected String inputPath;
		protected String trainShPath;
		protected int randomSeed;
		
		public ModelOneTry(String trainShPath, String inputPath, int randomSeed) {
			this.trainShPath = trainShPath;
			this.inputPath = inputPath;
			this.randomSeed = randomSeed;
		}
		
		public void run() {
			// train the model with one try
			// the command line is like "train.sh <input file> <number of state> <random seed> <ntries>"
			String res = exec(trainShPath + " " + inputPath + " 5 " + randomSeed + " 1");
			if (res.length() == 0) {
				log("model successfully built for seed " + randomSeed);
			} else {
				log("results for building model for seed " + randomSeed + ":");
				log(res);
			}
		}
		
		public String getInputDir() {
			int idx = inputPath.lastIndexOf(File.separatorChar);
			if (idx < 0)
				return "";
			else
				return inputPath.substring(0, idx);
		}
		
		public double getLValue() {
			try {
				int idx = inputPath.lastIndexOf('.');
				String path = inputPath.substring(0, idx+1) + "L";
				BufferedReader br = new BufferedReader(new FileReader(path));
				double ret = Double.parseDouble(br.readLine());
				br.close();
				return ret;
			} catch (Exception e) {
				e.printStackTrace();
				return 0;
			}
		}
	}
	
	/**
	 * @param args
	 */
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		if (args.length < 6) {
			System.out.println("Usage: java cgl.sensorgrid.sopac.gps.filters.RealtimeRdahmmRunner " +
								"commType nbHost nbPort subTopic pubTopic networkName");
			System.exit(0);
		}

		String commType = args[0];
		String nbHost = args[1];
		String nbPort = args[2];
		String subTopic = args[3];
		String pubTopic = args[4];
		String networkName = args[5];
		RealtimeRdahmmRunner test = new RealtimeRdahmmRunner(commType, nbHost, nbPort, subTopic, pubTopic, networkName);
	}

}
